package com.wssnail.elasticsearch.util;

import com.alibaba.fastjson.JSON;
import com.wssnail.elasticsearch.constants.MetricConstant;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.unit.Fuzziness;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.*;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.*;

/**
 * @Author: 熟透的蜗牛
 * @CreateTime: 2023-01-05 16:47
 * @Description: TODO
 * @Version: 1.0
 */
@Slf4j
public class ElasticSearchUtils {

    private RestHighLevelClient restHighLevelClient;

    private static final Integer MAX_PAGE_SIZE = 1000;

    public ElasticSearchUtils(RestHighLevelClient restHighLevelClient) {
        this.restHighLevelClient = restHighLevelClient;
    }

    /*
     * @description:创建索引
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 16:58
     * @param index
     * @return: boolean
     **/
    public boolean createIndex(String index) {
        try {
            if (isIndexExist(index)) {
                log.error("Index is  exits!");
                return false;
            }
            //1.创建索引请求
            CreateIndexRequest request = new CreateIndexRequest(index);
            //2.执行客户端请求
            CreateIndexResponse response = restHighLevelClient.indices()
                    .create(request, RequestOptions.DEFAULT);
            return response.isAcknowledged();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>createIndex>>>id>>>>>>{}", e);
        }
        return false;
    }

    /*
     * @description:判断索引是否存在
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 16:59
     * @param index
     * @return: boolean
     **/
    public boolean isIndexExist(String index) {
        try {
            GetIndexRequest request = new GetIndexRequest(index);
            return restHighLevelClient.indices().exists(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>isIndexExist>>>id>>>>>>{}", e);
        }
        return false;
    }

    /*
     * @description:删除索引
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:00
     * @param null
     * @return: null
     **/
    public boolean deleteIndex(String index) {
        try {
            if (!isIndexExist(index)) {
                log.error("Index is not exits!");
                return false;
            }
            DeleteIndexRequest request = new DeleteIndexRequest(index);
            AcknowledgedResponse delete = restHighLevelClient.indices()
                    .delete(request, RequestOptions.DEFAULT);
            return delete.isAcknowledged();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>deleteIndex>>>id>>>>>>{}", e);
        }
        return false;
    }

    /*
     * @description:更新数据，如果没有数据则新增
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:01
     * @param object 对象
     * @param index 索引名称
     * @param id 数据id
     * @return: java.lang.String
     **/
    public String submitDocument(Object object, String index, String id) {
        if (null == id) {
            return addDocument(object, index);
        }
        if (this.existsById(index, id)) {
            return this.updateDocumentByIdNoRealTime(object, index, id);
        } else {
            return addDocument(object, index, id);
        }
    }

    /*
     * @description:新增数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:03
     * @param object
     * @param index
     * @param id 数据id，为空时自动生成
     * @return: java.lang.String
     **/
    public String addDocument(Object object, String index, String id) {
        try {
            if (null == id) {
                return addDocument(object, index);
            }
            if (this.existsById(index, id)) {
                return this.updateDocumentByIdNoRealTime(object, index, id);
            }
            //创建请求
            IndexRequest request = new IndexRequest(index);
            request.id(id);
            request.timeout(TimeValue.timeValueSeconds(1));
            //将数据放入请求 json
            request.source(JSON.toJSONString(object), XContentType.JSON);
            //客户端发送请求
            IndexResponse response = restHighLevelClient.index(request, RequestOptions.DEFAULT);
            log.info("添加数据成功 索引为: {}, response 状态: {}, id为: {}", index, response.status().getStatus(), response.getId());
            return response.getId();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>addDocument>>>id>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:新增数据，id用UUID生成
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:05
     * @param object
     * @param index
     * @return: java.lang.String
     **/
    public String addDocument(Object object, String index) {
        try {
            return addDocument(object, index, UUID.randomUUID().toString().replaceAll("-", "").toUpperCase());
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>addDocument>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:根据id判断文档是否存在
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:07
     * @param index
     * @param id
     * @return: boolean
     **/
    public boolean existsById(String index, String id) {
        try {
            GetRequest request = new GetRequest(index, id);
            //不获取返回的_source的上下文
            request.fetchSourceContext(new FetchSourceContext(false));
            request.storedFields("_none_");
            return restHighLevelClient.exists(request, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>existsById>>>>>>{}", e);
        }
        return false;
    }

    /*
     * @description:通过id删除数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:08
     * @param index
     * @param id
     * @return: java.lang.String
     **/
    public String deleteDocumentById(String index, String id) {
        try {
            DeleteRequest request = new DeleteRequest(index, id);
            DeleteResponse deleteResponse = restHighLevelClient.delete(request, RequestOptions.DEFAULT);
            return deleteResponse.getId();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>deleteDocumentById>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:通过id修改数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:09
     * @param null
     * @return: null
     **/
    public String updateDocumentById(Object object, String index, String id) {
        try {
            UpdateRequest updateRequest = new UpdateRequest(index, id);
            updateRequest.timeout("1s");
            updateRequest.doc(JSON.toJSONString(object), XContentType.JSON);
            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            log.info("索引为: {}, id为: {},updateResponseID：{}, 更新数据成功", index, id, updateResponse.getId());
            return updateResponse.getId();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>updateDocumentById>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:通过id实时更新数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:11
     * @param object
     * @param index
     * @param id
     * @return: java.lang.String
     **/
    public String updateDocumentByIdNoRealTime(Object object, String index, String id) {
        try {
            //更新请求
            UpdateRequest updateRequest = new UpdateRequest(index, id);
            //保证数据实时更新
            updateRequest.setRefreshPolicy("wait_for");
            updateRequest.timeout("1s");
            updateRequest.doc(JSON.toJSONString(object), XContentType.JSON);
            //执行更新请求
            UpdateResponse updateResponse = restHighLevelClient.update(updateRequest, RequestOptions.DEFAULT);
            log.info("索引为: {}, id为: {},updateResponseID：{}, 实时更新数据成功", index, id, updateResponse.getId());
            return updateResponse.getId();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>updateDocumentByIdNoRealTime>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:通过id搜索数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:12
     * @param index
     * @param id
     * @param fields 多个字段用,分割
     * @return: java.util.Map<java.lang.String,java.lang.Object>
     **/
    public Map<String, Object> searchDocumentById(String index, String id, String fields) {
        try {
            GetRequest request = new GetRequest(index, id);
            if (StringUtils.isNotEmpty(fields)) {
                //只查询特定字段。如果需要查询所有字段则不设置该项。
                request.fetchSourceContext(new FetchSourceContext(true, fields.split(","), Strings.EMPTY_ARRAY));
            }
            GetResponse response = restHighLevelClient.get(request, RequestOptions.DEFAULT);
            return !response.isExists() ? new HashMap<>() : response.getSource();
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>查询失败searchDocumentById>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:批量插入数据
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:33
     * @param index
     * @param objects
     * @return: boolean
     **/
    public boolean bulkPost(String index, List<?> objects) {
        BulkRequest bulkRequest = new BulkRequest();
        BulkResponse response = null;
        //最大数量不得超过20万
        for (Object object : objects) {
            IndexRequest request = new IndexRequest(index);
            request.source(JSON.toJSONString(object), XContentType.JSON);
            bulkRequest.add(request);
        }
        try {
            response = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>bulkPost>>>>>>{}", e);
        }
        return null != response && !response.hasFailures();
    }


    /*
     * @description:高亮结果集
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:38
     * @param searchResponse
     * @param highlightField
     * @return: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     **/
    private List<Map<String, Object>> setSearchResponse(SearchResponse searchResponse, String highlightField) {
        //解析结果
        ArrayList<Map<String, Object>> list = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, HighlightField> high = hit.getHighlightFields();
            HighlightField title = high.get(highlightField);
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            //解析高亮字段,将原来的字段换为高亮字段
            if (title != null) {
                Text[] texts = title.fragments();
                StringBuilder nTitle = new StringBuilder();
                for (Text text : texts) {
                    nTitle.append(text);
                }
                //替换
                sourceAsMap.put(highlightField, nTitle.toString());
            }
            list.add(sourceAsMap);
        }
        return list;
    }


    /*
     * @description:高亮查询
     * @author:  熟透的蜗牛分页查询
     * @date: 2023/1/5 17:41
     * @param index
     * @param query
     * @param highlightField
     * @return: java.util.List<java.util.Map<java.lang.String,java.lang.Object>>
     **/
    public List<Map<String, Object>> searchListDocument(String index,
                                                        SearchSourceBuilder query,
                                                        String highlightField, Integer start, Integer pageSize) {
        try {
            SearchRequest request = new SearchRequest(index);
            //高亮
            HighlightBuilder highlight = new HighlightBuilder();
            highlight.field(highlightField);
            //关闭多个高亮
            highlight.requireFieldMatch(false);
            highlight.preTags("<span style='color:red'>");
            highlight.postTags("</span>");
            query.highlighter(highlight);
            query.from(start);
            query.size(pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize);
            request.source(query);
            SearchResponse response = restHighLevelClient.search(request, RequestOptions.DEFAULT);
            if (RestStatus.OK.getStatus() == (response.status().getStatus()) && response.getHits().getTotalHits().value > 0) {
                // 解析对象
                List<Map<String, Object>> maps = setSearchResponse(response, highlightField);
                return maps;
            }
        } catch (IOException e) {
            log.info(">>>>>>>>>>>>>>>searchListDocument>>>>>>{}", e);
        }
        return null;
    }


    /*
     * @description:精确查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/5 17:49
     * @param indexName
     * @param field
     * @param value
     * @param beanClass
     * @return: java.util.List<T>
     **/
    public <T> List<T> termQuery(String index, Object value, Class<T> beanClass, Integer start, Integer pageSize, String field) {
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize);
            searchSourceBuilder.query(QueryBuilders.termQuery(field, value));
            searchSourceBuilder.trackTotalHits(true);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>termQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:自定义查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/9 15:49
     * @param index
     * @param beanClass
     * @param query 查询条件
     * @return: java.util.List<T>
     **/
    public <T> List<T> selfDefine(String index, Class<T> beanClass, SearchSourceBuilder searchSourceBuilder) {
        List<T> list = new ArrayList<>();
        try {
            SearchRequest request = new SearchRequest(index);
            searchSourceBuilder.trackTotalHits(true);
            request.source(searchSourceBuilder);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>termQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:自定义查询文档数量
     * @author:  熟透的蜗牛
     * @date: 2023/1/9 15:56
     * @param indexName
     * @param searchSourceBuilder
     * @return: long
     **/
    public <T> long count(String indexName, SearchSourceBuilder searchSourceBuilder) {
        CountRequest countRequest = new CountRequest(indexName);
        countRequest.source(searchSourceBuilder);
        searchSourceBuilder.trackTotalHits(true);
        CountResponse countResponse;
        long count = 0L;
        try {
            countResponse = restHighLevelClient.count(countRequest, RequestOptions.DEFAULT);
            count = countResponse != null ? countResponse.getCount() : 0;
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>count>>>>>>{}", e);
        }
        return count;
    }

    /*
     * @description:多个查询在一个字段中
     * @author:  熟透的蜗牛
     * @date: 2023/1/9 14:39
     * @param index
     * @param field 字段
     * @param dataArgs 数值
     * @param beanClass 转化实体类
     * @param start
     * @param pageSize
     * @return: java.util.List<T>
     **/
    public <T> List<T> termsQuery(String index, String field, Object[] dataArgs, Class<T> beanClass, Integer start, Integer pageSize) {
        // 查询的数据列表
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.termsQuery(field, dataArgs));
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize);
            searchSourceBuilder.trackTotalHits(true);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>termsQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:根据查询交集查询设置分页
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 13:09
     * @param index
     * @param beanClass
     * @param startIndex
     * @param pageSize
     * @param orderList   -开头代表：倒序
     * @param fieldsList 多个字段
     * @param 1 and; 0-or
     * rangeList
     * @return: java.util.List<T>
     **/
    public <T> List<T> matchAllQuery(String index, Class<T> beanClass, int start, int pageSize,
                                     List<String> orderList, List<Map<String, Object>> fieldsList, Integer type) {
        // 查询的数据列表
        List<T> list = new ArrayList<>();
        try {
            // 创建查询源构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            // 构建查询条件
            if (null != fieldsList && fieldsList.size() > 0) {
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                for (Map map : fieldsList) {
                    Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Map.Entry<String, Object> next = iterator.next();
                        if (type == 1) {
                            boolQueryBuilder.must(QueryBuilders.matchQuery(next.getKey(), next.getValue()).operator(Operator.AND));
                        } else {
                            boolQueryBuilder.must(QueryBuilders.matchQuery(next.getKey(), next.getValue()).operator(Operator.OR));
                        }
                    }
                    searchSourceBuilder.query(boolQueryBuilder);
                }
            } else {
                MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
                searchSourceBuilder.query(matchAllQueryBuilder);
            }
            // 设置分页
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize);
            searchSourceBuilder.trackTotalHits(true);
            // 设置排序
            if (orderList != null) {
                for (String order : orderList) {
                    boolean flag = order.startsWith("-");
                    SortOrder sort = flag ? SortOrder.DESC : SortOrder.ASC;
                    order = flag ? order.substring(1) : order;
                    searchSourceBuilder.sort(order, sort);
                }
            }
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (IOException e) {
            log.info(">>>>>>>>>>>>>>>matchAllQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:词语匹配查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 13:26
     * @param index 索引名称
     * @param beanClass
     * @param field
     * @param value
     * @return: java.util.List<T>
     **/
    public <T> List<T> matchPhraseQuery(String index, Class<T> beanClass, String field, Object value) {
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.matchPhraseQuery(field, value));
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (IOException e) {
            log.info(">>>>>>>>>>>>>>>matchPhraseQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:内容在多字段查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/9 15:27
     * @param index
     * @param beanClass
     * @param fields
     * @param text
     * @param start 起始位置
     * @param pageSize 页容量
     * @return: java.util.List<T>
     **/
    public <T> List<T> matchMultiQuery(String index, Class<T> beanClass, String[] fields, Object text, Integer start, Integer pageSize) {
        // 查询的数据列表
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(text, fields));
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize);
            searchSourceBuilder.trackTotalHits(true);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>matchMultiQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description: 通配符查询(wildcard)：会对查询条件进行分词。还可以使用通配符 ?（任意单个字符） 和 * （0个或多个字符）
     * *：表示多个字符（0个或多个字符）
     * ?：表示单个字符
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 15:02
     * @param index
     * @param beanClass
     * @param field
     * @param text
     * @return: java.util.List<T>
     **/
    public <T> List<T> wildcardQuery(String index, Class<T> beanClass, String field, String text, Integer start, Integer pageSize) {
        // 查询的数据列表
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.wildcardQuery(field, text));
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize > MAX_PAGE_SIZE ? MAX_PAGE_SIZE : pageSize);
            searchSourceBuilder.trackTotalHits(true);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>wildcardQuery>>>>>>{}", e);
        }
        return list;
    }


    /*
     * @description:模糊查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/9 15:34
     * @param index
     * @param beanClass
     * @param field
     * @param text
     * @param start
     * @param pageSize
     * @return: java.util.List<T>
     **/
    public <T> List<T> fuzzyQuery(String index, Class<T> beanClass, String field, String text, Integer start, Integer pageSize) {
        // 查询的数据列表
        List<T> list = new ArrayList<>();
        try {
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(QueryBuilders.fuzzyQuery(field, text).fuzziness(Fuzziness.AUTO));
            searchSourceBuilder.from(start);
            searchSourceBuilder.size(pageSize);
            searchSourceBuilder.trackTotalHits(true);
            queryEsData(index, beanClass, list, searchSourceBuilder);
        } catch (IOException e) {
            log.info(">>>>>>>>>>>>>>>fuzzyQuery>>>>>>{}", e);
        }
        return list;
    }

    /*
     * @description:
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 15:34
     * @param index
     * @param type 常用的操作有：avg：求平均、max：最大值、min：最小值、sum：求和
     * @param field
     **/
    public Double metricQuery(String index, String type, String field) {
        try {
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            if (MetricConstant.MAX.equals(type)) {
                AggregationBuilder max = AggregationBuilders.max(MetricConstant.MAX + type).field(field);
                searchSourceBuilder.aggregation(max);
            }
            if (MetricConstant.MIN.equals(type)) {
                AggregationBuilder min = AggregationBuilders.min(MetricConstant.MIN + type).field(field);
                searchSourceBuilder.aggregation(min);
            }
            if (MetricConstant.AVG.equals(type)) {
                AvgAggregationBuilder avg = AggregationBuilders.avg(MetricConstant.AVG + type).field(field);
                searchSourceBuilder.aggregation(avg);
            }
            if (MetricConstant.SUM.equals(type)) {
                SumAggregationBuilder sum = AggregationBuilders.sum(MetricConstant.SUM + type).field(field);
                searchSourceBuilder.aggregation(sum);
            }
            SearchRequest searchRequest = new SearchRequest(index);
            searchRequest.source(searchSourceBuilder);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            if (MetricConstant.MAX.equals(type)) {
                ParsedMax max = aggregations.get(MetricConstant.MAX + type);
                return max.getValue();
            }
            if (MetricConstant.MIN.equals(type)) {
                ParsedMin min = aggregations.get(MetricConstant.MIN + type);
                return min.getValue();
            }
            if (MetricConstant.AVG.equals(type)) {
                ParsedAvg avg = aggregations.get(MetricConstant.AVG + type);
                return avg.getValue();
            }
            if (MetricConstant.SUM.equals(type)) {
                ParsedSum sum = aggregations.get(MetricConstant.SUM + type);
                return sum.getValue();
            }
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>metricQuery>>>>>>{}", e);
        }
        return null;
    }

    /*
     * @description:分组聚合查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 16:23
     * @param indexName
     * @param bucketField
     * @param bucketFieldAlias
     * @return:
     **/
    public void bucketQuery(String index, String bucketField, String bucketFieldAlias) {
        try {
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            TermsAggregationBuilder aggBrandName = AggregationBuilders.terms(bucketFieldAlias).field(bucketField);
            searchSourceBuilder.aggregation(aggBrandName);
            SearchRequest searchRequest = new SearchRequest(index);
            searchRequest.source(searchSourceBuilder);
            // 执行查询，然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            ParsedStringTerms aggBrandName1 = aggregations.get(bucketField); // 分组结果数据
            for (Terms.Bucket bucket : aggBrandName1.getBuckets()) {
                log.info(bucket.getKeyAsString() + "====" + bucket.getDocCount());
            }
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>bucketQuery>>>>>>{}", e);
        }
    }

    /*
     * @description:分组后的聚合查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 16:39
     * @param index
     * @param bucketField 分组字段
     * @param bucketFieldAlias
     * @param avgFiled 求平均值的字段
     * @param avgFiledAlias
     **/
    public void subBucketQuery(String index, String bucketField, String bucketFieldAlias, String avgFiled, String avgFiledAlias) {
        try {
            // 构建查询条件
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            // 创建查询源构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);
            // 根据 bucketField进行分组查询,并且获取分类信息中 指定字段的平均值
            TermsAggregationBuilder subAggregation = AggregationBuilders.terms(bucketFieldAlias).field(bucketField)
                    .subAggregation(AggregationBuilders.avg(avgFiledAlias).field(avgFiled));
            searchSourceBuilder.aggregation(subAggregation);
            // 创建查询请求对象，将查询对象配置到其中
            SearchRequest searchRequest = new SearchRequest(index);
            searchRequest.source(searchSourceBuilder);
            // 执行查询，然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            Aggregations aggregations = searchResponse.getAggregations();
            ParsedStringTerms aggBrandName1 = aggregations.get(bucketFieldAlias);
            for (Terms.Bucket bucket : aggBrandName1.getBuckets()) {
                // 获取聚合后的 组内字段平均值,注意返回值不是Aggregation对象,而是指定的ParsedAvg对象
                ParsedAvg avgPrice = bucket.getAggregations().get(avgFiledAlias);
                log.info(bucket.getKeyAsString() + "====" + avgPrice.getValueAsString());
            }
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>subBucketQuery>>>>>>{}", e);
        }
    }

    /*
     * @description:综合聚合查询
     * @author:  熟透的蜗牛
     * @date: 2023/1/6 17:11
     * @param:
     * @param index
     **/
    public void subSubAgg(String index) {
        try {
            // 构建查询条件
            MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
            // 创建查询源构造器
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            searchSourceBuilder.query(matchAllQueryBuilder);

            // 注意这里聚合写的位置不要写错,很容易搞混,错一个括号就不对了
            TermsAggregationBuilder subAggregation = AggregationBuilders.terms("categoryNameAgg").field("categoryName")
                    .subAggregation(AggregationBuilders.avg("categoryNameAvgPrice").field("price"))
                    .subAggregation(AggregationBuilders.terms("brandNameAgg").field("brandName")
                            .subAggregation(AggregationBuilders.avg("brandNameAvgPrice").field("price")));
            searchSourceBuilder.aggregation(subAggregation);
            // 创建查询请求对象，将查询对象配置到其中
            SearchRequest searchRequest = new SearchRequest(index);
            searchRequest.source(searchSourceBuilder);
            // 执行查询，然后处理响应结果
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            //获取总记录数
            log.info("totalHits = " + searchResponse.getHits().getTotalHits());
            // 获取聚合信息
            Aggregations aggregations = searchResponse.getAggregations();
            ParsedStringTerms categoryNameAgg = aggregations.get("categoryNameAgg");
            //获取值返回
            for (Terms.Bucket bucket : categoryNameAgg.getBuckets()) {
                // 获取聚合后的分类名称
                String categoryName = bucket.getKeyAsString();
                // 获取聚合命中的文档数量
                long docCount = bucket.getDocCount();
                // 获取聚合后的分类的平均价格,注意返回值不是Aggregation对象,而是指定的ParsedAvg对象
                ParsedAvg avgPrice = bucket.getAggregations().get("categoryNameAvgPrice");
                System.out.println(categoryName + "======平均价:" + avgPrice.getValue() + "======数量:" + docCount);
                ParsedStringTerms brandNameAgg = bucket.getAggregations().get("brandNameAgg");
                for (Terms.Bucket brandeNameAggBucket : brandNameAgg.getBuckets()) {
                    // 获取聚合后的品牌名称
                    String brandName = brandeNameAggBucket.getKeyAsString();
                    // 获取聚合后的品牌的平均价格,注意返回值不是Aggregation对象,而是指定的ParsedAvg对象
                    ParsedAvg brandNameAvgPrice = brandeNameAggBucket.getAggregations().get("brandNameAvgPrice");
                    log.info("     " + brandName + "======" + brandNameAvgPrice.getValue());
                }
            }
        } catch (Exception e) {
            log.info(">>>>>>>>>>>>>>>subSubAgg>>>>>>{}", e);
        }
    }

    private <T> void queryEsData(String indexName, Class<T> beanClass, List<T> list, SearchSourceBuilder searchSourceBuilder)
            throws IOException {
        // 创建查询请求对象，将查询对象配置到其中
        SearchRequest searchRequest = new SearchRequest(indexName);
        searchRequest.source(searchSourceBuilder);
        // 执行查询，然后处理响应结果
        log.info("DSL语句为：{}", searchRequest.source().toString());
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
        // 根据状态和数据条数验证是否返回了数据
        if (RestStatus.OK.equals(searchResponse.status()) && searchResponse.getHits().getTotalHits().value > 0) {
            SearchHits hits = searchResponse.getHits();
            for (SearchHit hit : hits) {
                // 将 JSON 转换成对象
                T bean = JSON.parseObject(hit.getSourceAsString(), beanClass);
                list.add(bean);
            }
        }
    }

}
